package com.example.test_event_and_callback.infras.async;

import com.example.test_event_and_callback.impl.TestProviderService;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

public class AsyncExecutor<ProviderMethodsType> {

    private Map<Class<?>, AsyncDemanderProcessor<?>> demanderProcessorMap;

    private ThreadPoolExecutor taskPool;

    public Map<Class<?>, AsyncDemanderProcessor<?>> getDemanderProcessorMap() {
        return demanderProcessorMap;
    }

    public void setTaskPool(ThreadPoolExecutor taskPool) {
        this.taskPool = taskPool;
    }

    public <T> T execute(T demanderObj, String str){
        AsyncDemanderProcessor<?> demanderProcessor = demanderProcessorMap.get(demanderObj.getClass());
        AsyncProviderProcessor<?> providerProcessor = demanderProcessor.getProviderProcessor();
        //没有继承Demander类的就包一层代理
        Demander demander = (demanderObj instanceof Demander) ? (Demander) demanderObj : new AsyncDemanderProxy(demanderObj);
        Map<String, ?> methodHandleMap = providerProcessor.getProviderMethodMap();
        List<CompletableFuture<Void>> futureList = executeMethodCall(methodHandleMap, demander, str, demanderProcessor, providerProcessor);
        //获取执行结果
        CompletableFuture<Void> allDoneFuture = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]));
        try {
            // 等待所有future完成，返回数据
            allDoneFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException("异步操作中断或执行异常", e);
        }
        return demanderObj;
    }

    private List<CompletableFuture<Void>> executeMethodCall(
            Map<String, ?> methodMap,
            Demander demander,
            String str,
            AsyncDemanderProcessor<?> demanderProcessor,
            AsyncProviderProcessor<?> providerProcessor
    ) {
        return methodMap.entrySet().stream().map(entry -> CompletableFuture.runAsync(() -> {
            try {
                Object providerData = providerProcessor.executeProviderMethod(entry.getValue(), new TestProviderService(), str);
                demanderProcessor.setParam(demander, entry.getKey(), providerData);
            } catch (Throwable e) {
                throw new RuntimeException("方法调用失败", e);
            }
        }, taskPool)).toList();
    }

    public void setDemanderProcessorMap(Map<Class<?>, AsyncDemanderProcessor<?>> demanderProcessorMap) {
        this.demanderProcessorMap = demanderProcessorMap;
    }

}
